package main

import "fmt"

/*
作业：实现电梯核心功能
- 电梯在没有人按按钮的时候停留在当前楼层不动
- 当有人按电梯后，电梯即刻出发到达对应楼层
- 电梯将乘客送往目的楼层，每秒钟走一层
- 如果有多人按电梯，电梯按照如下规则行进：
    -- 电梯向第一个按按钮的楼层出发
    -- 如果中途有其他楼层也按了，到对应楼层时暂停、开门、关门，重新继续原来方向行进
    -- 如果已经到达目的地，但还有同方向的目的楼层时，电梯维持原有方向继续前进，直到该方向最后一个楼层
    -- 到达最后一个目的后，如果另一个方向还有未到达楼层，则电梯调转方向，逐个送到最后目的地，直到所有目标都送达

 测试案例：
 1. 楼层有5层， 所有楼层没有人请求电梯，电梯不动
 2. 楼层有5层，电梯在1层，三楼有人按电梯，电梯上到三楼，并停在3楼
 3. 楼层有5层，电梯在3层， 上了一些人，目标楼层4楼和2楼，电梯先上4楼，在调转方向到2楼，停在2楼
 4. 楼层有5层，电梯在3层， 上了一些人，目标楼层4楼、5楼和2楼，电梯先上4楼，然后到5楼，调转方向到2楼，停在2楼

要求：
使用面向对象设计（封装）
所有函数、成员方法符合面向对象要求
*/

var (
	//电梯对象
	ele = MakeElevator(6, -3, 1)
	//第一个摁下的电梯目标
	runFirst = 0
	//确定顺序
	num = 0
)

func main() {
	//调用运行程序
	ActionElevator()
}

//电梯存储类型
type Elevator struct {
	//楼层顺序切片
	Targets []int
	//楼层是否被摁下储存
	TargetsStatus map[int]int
	//运行状态
	GoState int
	//当前所在楼层
	Present int
	//当前楼层对应切片坐标
	PresentTarget int
}

//构造电梯对象
func MakeElevator(maxfloors int, minfloors int, present int) Elevator {
	var ele Elevator
	var slice1 []int
	var TargetsStatus = make(map[int]int)
	var getnum = 0
	for i := minfloors; i <= maxfloors; i++ {
		if i != 0 {
			if i == present {
				ele.PresentTarget = getnum
			}
			slice1 = append(slice1, i)
			TargetsStatus[i] = 0
			getnum++
		}
	}
	ele.TargetsStatus = TargetsStatus
	ele.Targets = slice1
	ele.GoState = 0
	ele.Present = present
	return ele
}

//电梯运行
func ActionElevator() {
	var target int
	var startnum = ele.Targets[len(ele.Targets)-1] + 1
	for {
		fmt.Println("电梯已启动 当前楼层", ele.Present, " 输入需要去的楼层", ele.Targets[0], "-", ele.Targets[len(ele.Targets)-1], "（输入0关闭电梯，输入", startnum, "电梯启动）")
		fmt.Scan(&target)
		if target == 0 {
			break
		}
		if target > startnum {
			fmt.Println("输入的楼层不存在")
			continue
		}
		if target == startnum {
			for {
				if !HaveTarger(ele.Targets) {
					fmt.Println("电梯无任务")
					break
				}
				SetDirection()
				ElevatorMove()
			}
		} else {
			if num == 0 {
				runFirst = target
			}
			num++
			SetActhon(target)
		}
	}
}

//设置电梯目标
func SetActhon(target int) {
	if ele.TargetsStatus[target] == 1 {
		fmt.Println("已取消该楼", target, "层")
		ele.TargetsStatus[target] = 0
		if num == 1 {
			num = 0
		}
	} else {
		ele.TargetsStatus[target] = 1
		if target == ele.Present {
			fmt.Println("已在该楼层,请重新输入")
			SetActhon(target)
		}
	}
}

//电梯移动
func ElevatorMove() {
	switch ele.GoState {
	case 1:
		for i := ele.PresentTarget; i < len(ele.Targets); i++ {
			ele.Present = ele.Targets[i]
			ele.PresentTarget = i
			if ele.TargetsStatus[ele.Targets[i]] == 1 {
				ele.TargetsStatus[ele.Targets[i]] = 0
				fmt.Println(ele.Present, "层,到了,请注意脚下安全")
				if !HaveTarger(ele.Targets[i:]) {
					if HaveTarger(ele.Targets[:i]) {
						chengDirection()
					}
					break
				}
			}
			fmt.Println("电梯上行,当前为", ele.Present, "层")
		}

	case 2:
		for i := ele.PresentTarget; i >= 0; i-- {
			ele.Present = ele.Targets[i]
			ele.PresentTarget = i
			if ele.TargetsStatus[ele.Targets[i]] == 1 {
				ele.TargetsStatus[ele.Targets[i]] = 0
				fmt.Println(ele.Present, "层,到了,请注意脚下安全")
				if !HaveTarger(ele.Targets[i:]) {
					if HaveTarger(ele.Targets[:i]) {
						chengDirection()
					}
					break
				}
			}
			fmt.Println("电梯下行,当前为", ele.Present, "层")
		}
	case 0:
		fmt.Println("电梯正在等待")
	}
	num = 0
}

//判断是否存在目标数
func HaveTarger(arr []int) bool {
	var isOK = false
	for i := 0; i < len(arr); i++ {
		if ele.TargetsStatus[arr[i]] == 1 {
			isOK = true
			break
		}
	}
	return isOK
}

//设置方向
func SetDirection() {
	switch ele.Present {
	case ele.Targets[len(ele.Targets)-1]:
		ele.GoState = 2
	case ele.Targets[0]:
		ele.GoState = 1
	default:
		if ele.Present < runFirst {
			ele.GoState = 1
		} else {
			ele.GoState = 2
		}

	}
}

//改变方向
func chengDirection() {
	for i := 0; i < len(ele.Targets); i++ {
		if ele.TargetsStatus[ele.Targets[i]] == 1 {
			runFirst = i
			break
		}
	}
}
